package main
import (
	"fmt"
	"flag"  //Go语言标准库提供了用于快迅解析命令行参数的 flag 包
	"bufio"
	"io"
	"os"
	"strconv"
	"time"
	// "E:/workspace/Go/application/sorter/sorter/algorithms/bubblesort"
	// "E:/workspace/Go/application/sorter/sorter/algorithms/qsort"
	"algorithms/bubblesort"
	"algorithms/qsort"
	)


// 定义一下排序算法函数的函数原型
// func QuickSort(in []int)[]int
// func BubbleSort(in []int)[]int

// 	1 获取并解析命令行输入；
var infile *string = flag.String("i", "infile", "File contains values for sorting")
var outfile *string = flag.String("o", "outfile", "File to receive sorted values")
var algorithm *string = flag.String("a", "qsort", "Sort algorithm")
/*
go run sorter.go -i 1.txt -o 2.txt -a qsort
go run sorter.go -o 2.txt -a qsort -i 1.txt
输入的参数顺序完全无关，输出结果都一样
infile= 1.txt  outfile= 2.txt  algorithm= qsort

也可以通过编译之后调用此程序
go build sorted.go
sorter.exe  -o 2.txt -a qsort -i 1.txt
*/


//  2 从对应文件中读取输入数据；（考虑文件不存在的问题）
// 需要先从一个文件中把包含的内容读取到数组中，将该数组排好序后再写回到另一个文
// 件中，因此还需要学习如何在Go语言中操作文件。
func readValues(infile string)(values []int, err error){
	file, err := os.Open(infile)
	if err != nil{
		fmt.Println("Failed to open the input file ", infile)
		return
	}

	defer file.Close()   //使用 defer 关键字以确保关闭文件句柄

	br := bufio.NewReader(file)
	values =  make([]int, 0)  //数组切片的使用

	for{
		line, isPrefix, err1 := br.ReadLine()

		if err1 != nil {
			if err1 != io.EOF {
				err = err1
			}
			break
		}

		if isPrefix{
			fmt.Println("A too long line, seems unexpected.")
			return
		}

		str := string(line) // 转换字符数组为字符串

		value, err1 := strconv.Atoi(str)

		if err1 != nil{
			err = err1
			return
		}

		values = append(values,value)
	}
	return
}
/*
该函数用到了 os 、 io 、 bufio 和 strconv 等Go语言标准库中的包，用于文件读写和字符串处理。
熟练掌握这些包的基本用法，将会大幅度提高使用Go语言的工作效率。
*/


//  3 调用对应的排序函数；


//  4 将排序的结果输出到对应的文件中；(若果指定的输出文件不存在，则程序应该自动创建该文件)
func writeValues(values []int, outfile string) error{
	file, err := os.Create(outfile)
	if err != nil{
		fmt.Println("Failed to create the output file ",outfile)
		return err
	}

	defer file.Close()

	for _, value := range values{
		str := strconv.Itoa(value)
		file.WriteString(str + "\r\n") //此处在win上需要使用\r\n来对写入文件的内容进行换行  linux上只需要使用\n即可
	}
	return nil
}

//  5 打印排序所花费时间的信息。


func main(){
	flag.Parse()

	if infile != nil{
		fmt.Println("infile=",*infile, " outfile=", *outfile, " algorithm=", *algorithm)
	}

	values, err := readValues(*infile)
	if err == nil{
		t1 := time.Now()
		fmt.Println("Read values:", values)
		switch *algorithm{
		case "qsort":
			qsort.QuickSort(values)  //通过包名调用包里面的函数
		case "bubblesort":
			bubblesort.BubbleSort(values)
		default:
			fmt.Println("Sorting algorithm", *algorithm, "is either unknown or unsupprted.")
		}

		err1 := writeValues(values, *outfile)
		if err1 == nil{
			fmt.Println("保存文件成功", err1)
		}else{
			fmt.Println("保存失败", err1)
		}

		t2 := time.Now()
		fmt.Println("The sorting process costs ", t2.Sub(t1)," to complete.")
	}else{
		fmt.Println(err)
	}
}
